<?php
// +-------------------------------------------------------------------
// | 
// +-------------------------------------------------------------------
// | Copyright (c) 2009-2016 All rights reserved.
// +-------------------------------------------------------------------

/**
 * 业务组件加载器
 *
 * @param mixed $className
 *            service对象名或对象实例
 * @param array $param
 * @return Object <ServiceWrapper>
 */
function O($className)
{
    static $instances = array();

    //支持指定用哪个service
    $classFullName = class_exists($cf = '\\' . $className . '\\Service') ? $cf : '\\Service\\' . ucfirst($className) . '\\Service';

    class_exists($classFullName) or $classFullName = '\\Kcdns' . $classFullName;

    if (!isset($instances[$classFullName])) {
        $instances[$classFullName] = new ServiceWrapper(is_object($className) ? $className : new $classFullName(), $classFullName);
    }

    return $instances[$classFullName];
}

/**
 * 业务组件加载器(抛出异常)
 *
 * @param mixed $className
 *            service对象名或对象实例
 * @param array $param
 * @return Object <ServiceWrapper>
 */
function OE($className)
{
    return O($className, null)->throwException();
}

/**
 * 业务组件包装器
 * 提供统一的异常处理
 *
 * @author Sadaharu#1 <hechengyuan@ucfgroup.com>
 */
class ServiceWrapper
{

    protected $classId = '';

    protected $error = '';

    protected $exception = null;

    protected $errorCode = 0;

    protected $serviceInstance;

    protected $cache = false;

    protected $throwException = false;

    public function __construct($serviceInstance, $classId)
    {
        $this->classId = $classId;
        $this->serviceInstance = $serviceInstance;
    }

    /**
     * 获取异常提示消息
     */
    public function getError()
    {
        if ($this->error == '') {
            return '';
        }

        // 不存在对应的翻译时, 返回通用错误消息
        $errorLabel = L($this->error);
        $errorLabel == strtoupper($this->error) and $errorLabel = $this->error;

        return $this->errorCode ? '[' . $this->errorCode . ']' . $errorLabel : $errorLabel;
    }

    public function getException()
    {
        return $this->exception;
    }

    /**
     * 自动缓存机制
     */
    public function getCache($cacheTime = 1800)
    {
        $this->cache = $cacheTime;
        return $this;
    }

    /**
     * 继续抛出异常
     */
    public function throwException()
    {
        $this->throwException = true;
        return $this;
    }

    /**
     * 加载字典
     */
    public function dic($key, $value = null)
    {
        $dicClassName = substr($this->classId, 0, strrpos($this->classId, "\\")) . "\\Dic";
        return $dicClassName::get($key, $value);
    }

    function __call($method, $params)
    {
        $e = null;
        $return = false;
        $cachename = null;
        $cache = $this->cache;
        $throwException = $this->throwException;

        $this->throwException = false;
        $this->throwExceptionType = false;
        $this->cache = false;

        if ($cache) {
            $cachename = md5($this->classId . $method . serialize($params));
            $return = S($cachename);
        }

        try {
            if (!method_exists($this->serviceInstance, $method)) {
                throw new Exception("Method not exists : {$this->classId}::{$method}");
            }

            if (!$return) {
                $return = call_user_func_array(array(
                    $this->serviceInstance,
                    $method
                ), $params);

                $cache and $return and S($cachename, $return, $cache);
            }
        } catch (\InvalidParamException $e) {
            $this->exception = $e;
            $this->error = $e->getMessage();
            $this->errorCode = $e->getCode();
        } catch (\Exception $e) {
            $this->exception = $e;
            $this->error = $e->getMessage();
            $this->errorCode = $e->getCode();
            \KCSLog::DEBUG($e);
        }

        if ($throwException && $e) {
            $GLOBALS['THINK_PHP_404'] = true;
            throw $e;
        }

        return $return;
    }
}

class InvalidParamException extends \Exception
{

    public function __construct($message = "", $code = 10002, Throwable $previous = null)
    {
        parent::__construct($message, $code, $previous);
    }
}

